#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <signal.h>
#include <string.h>
#include <pthread.h>
#include "EM9118_fun.h"
#include "zt_pm518_ioctl.h"
#include "zt_net.h"
#include "log.h"
#include "zcd_timer.h"

#define AD_WF_MAX 29490 //32767 * 0.9
ZcdTimer tv;

//extern DevPara devPara;
U32 g_adEnCh = 0x3ffff;
pthread_mutex_t ebiLock;

int EM9118_Init()
{
	pthread_mutex_init( &ebiLock, PTHREAD_MUTEX_TIMED_NP );
	char* dev = { "/dev/sama5d3x-ebi-1" };
	int fd = open(dev, O_RDWR);
	if (fd <= 0) {
		printf("open dev error!\n");
		return -1;
	}
	return fd;
}

int EM9118_WriteM( int fd, U32 ulAddr, U32 ulData )
{
	U32 ul[2] = { ulAddr, ulData };
	int nRet = ioctl( fd, PM518_IOC_WRITE_MEM, ul );
	return nRet;
}

U32 EM9118_ReadM( int fd, U32 ulAddr )
{
	U32 ul = ulAddr;
	ioctl( fd, PM518_IOC_READ_MEM, &ul );
	//  log_write( "%x", ul );
	return ul;
}

int EM9118_Outw( int fd, U32 ulAddr, U32 ulData )
{
	U32 ul[2] = { ulAddr, ulData };
	pthread_mutex_lock( &ebiLock );
	int nRet = ioctl( fd, PM518_IOC_OUTW, ul );
	pthread_mutex_unlock( &ebiLock );
//	log_write( "EM9118_Outw:%d,0x%x", ulAddr, ulData );
	return nRet;
}

U16 EM9118_Inw( int fd, U32 ulAddr )
{
	U32 ul = ulAddr;
	pthread_mutex_lock( &ebiLock );
	ioctl( fd, PM518_IOC_INW, &ul );
	pthread_mutex_unlock( &ebiLock );
	//  log_write( "%x", ul );
	return ul & 0xffff;
}

int EM9118_Outb( int fd, U32 ulAddr, U32 ulData )
{
	U32 ul[2] = { ulAddr, ulData };
	pthread_mutex_lock( &ebiLock );
	int nRet = ioctl( fd, PM518_IOC_OUTW, ul );
	pthread_mutex_unlock( &ebiLock );
	return nRet;
}

U8 EM9118_Inb( int fd, U32 ulAddr )
{
	U32 ul = ulAddr;
	pthread_mutex_lock( &ebiLock );
	ioctl( fd, PM518_IOC_INW, &ul );
	pthread_mutex_unlock( &ebiLock );
	//  log_write( "%x", ul );
	return ul & 0xff;
}

U32 EM9118_IODiAll( int fd )
{
	U32 io1to8 = 0;
	U32 ulRet = 0;
	io1to8 = EM9118_Inb( fd, ADDR_DI1TO4 );
	ulRet = io1to8;
	return ulRet;
}

U32 EM9106_IODiAll( int fd )
{
	U32 io1to16 = EM9118_Inw( fd, ADDR_IO1TO16 ) & 0xffff;
	U32 io17to24 = EM9118_Inb( fd, ADDR_IO17TO24 ) & 0xff;
	U32 ulRet = io1to16 | (io17to24 << 16);
	printf( "io1to16:%x,io17to24:%x, %x\n", io1to16, io17to24, ulRet );
	return ulRet;
}

I32 EM9118_IODoAll( int fd, U32 ulStateAll )
{
	EM9118_Outb( fd, ADDR_DO1TO2, ulStateAll );
	return 0;
}

I32 EM9106_IODoAll( int fd, U32 ulStateAll )
{
	EM9118_Outw( fd, ADDR_IO1TO16, ulStateAll & 0xffff );
	EM9118_Outb( fd, ADDR_IO17TO24, (ulStateAll>>16)&0xff );
//	log_write( "EM9106_IODoAll %x", ulStateAll );
	return 0;
}

I32 EM9106_IOSetDir( int fd, U32 dir )
{
	EM9118_Outb( fd, ADDR_DIR, dir );
	return 0;
}

I32 EM9106_IOSetMode( int fd, U8 ioMode )
{
	U8 realMode = 0;
	int i;
	for( i = 0; i < 4; ++i )
	{
		if( (ioMode>>i)&1 )
			realMode |= 1 << (i*2);
	}
	EM9118_Outb( fd, ADDR_IOCTRL, realMode );
	return 0;
}

/*I32 EM9118_StateToDo( int fd,  int doCh, int value)
{
	if (value)
		devPara.doValue &= ~(1<<(doCh-1));
	else
		devPara.doValue |= 1<<(doCh-1);
	EM9118_Outb( fd, ADDR_DO1TO2, devPara.doValue );
	return 0;
}*/

I32 EM9118_IRQEnable( int fd, U32 irqInx )
{
	return ioctl( fd, PM518_IOC_ENABLEIRQ, &irqInx );
}

I32 EM9118_IRQDisable( int fd )
{
	return ioctl( fd, PM518_IOC_DISABLEIRQ, NULL );
}

I32 EM9118_ADSetCh( int fd, U32 enCh )
{
	int i, bits=0;
	g_adEnCh = enCh;
	EM9118_Outw( fd, ADDR_ADCH1T16, enCh & 0xffff );
	EM9118_Outw( fd, ADDR_ADCH17T18, (enCh>>16)&3 );

	EM9118_IOInFifo( fd, (enCh >> 22)&3 );

	for(i=0; i<CT_CH_COUNT; i++)
		if ((enCh>>26) & (1<<i))
		  bits += 3<<(i*2);
	EM9118_Outw( fd, ADDR_CTCH, bits );

	//log_write("%s: enCh: %x, CT:%x", __FUNCTION__, enCh, bits);

	return EM9118_Outw( fd, ADDR_ECCH,  ((enCh>>24)&3) | (((enCh>>30)&3)<<2));
}

U32 EM9118_ADGetCh( int fd )
{
	return g_adEnCh;
}

I32 EM9118_HCSetChFreq( int fd, U16* freqDiv )
{
	int pos=0;
	int i;

	for(i=0; i<AD_CH_COUNT/2; i++)
	{
		EM9118_Outw( fd, ADDR_CHFREQDIV_BASE+i, freqDiv[pos] + (freqDiv[pos+1]<<8));
//		log_write("EM9118_HCSetChFreq: set addr:%d val:%d", ADDR_CHFREQDIV_BASE+i, freqDiv[pos] + (freqDiv[pos+1]<<8));
		pos += 2;
	}
	return 0;
}

I32 EM9118_HCSetGroupFreq( int fd, U32 groupFreqDiv )
{
	EM9118_Outw( fd, ADDR_GROUPFREQDIV_L, groupFreqDiv & 0xffff );
	return EM9118_Outw( fd, ADDR_GROUPFREQDIV_H, groupFreqDiv / 65536 );
}

I32 EM9118_HCStart( int fd, U32 startMode )
{//注意调用此函数之前一定要先调用EM9118_SFifoResize
	EM9118_HCStop( fd );
	EM9118_HFifoClear( fd );
	
	U32 ctrlCode = startMode;
//	log_write( "EM9118_HCStart:%x", ctrlCode );
	return EM9118_Outw( fd, ADDR_CTRLCODE, ctrlCode );
}

I32 EM9118_HCStop( int fd )
{
	//因为涉及到中断相关操作，所以需要告诉内核调用了采集停止命令。
	ioctl( fd, PM518_IOC_ADSTOP, NULL );
	return EM9118_Outw( fd, ADDR_CTRLCODE, 0 );
}

I32 EM9118_HFifoClear( int fd )
{
	return EM9118_Outw( fd, ADDR_CTRLCODE, 0 );
}

U32 EM9118_ADSFifoCanReadNumber( int fd )
{
	U32 canReadNumber = 0;
	ioctl( fd, PM518_IOC_ADSFIFOCANREADNUM, &canReadNumber );
	return canReadNumber;
}

U32 EM9118_DaSFifoCanReadNumber( int fd )
{
	U32 canReadNumber = 0;
	ioctl( fd, PM518_IOC_DASFIFOCANREADNUM, &canReadNumber );
	return canReadNumber;
}

U32 EM9118_SFifoResize( int fd, int chCount )
{//主要是起到清空内核SFIFO的作用,并且将内核缓冲区设为通道整数倍
	ioctl( fd, PM518_IOC_FIFO_RESIZE, &chCount );
	return 0;
}

U32 EM9118_DaSFifoClear( int fd )
{//清空DA软件FIFO
	ioctl( fd, PM518_IOC_DAFIFOCLEAR, NULL );
	return 0;
}

I32 EM9118_ADReadSFifo( int fd, U16* pCode, U32 itemsCount )
{
	int itemSize = sizeof( U16 );
	size_t bytesCount = itemsCount * itemSize;
	ssize_t retRead = read( fd, pCode, bytesCount );
	U32 retItemsCount;
	if( retRead < 0 )  //failed
		return retRead;
	retItemsCount = retRead / itemSize;
	return retItemsCount;
}

I32 EM9118_DaWriteSFifo( int fd, U16* pCode, U32 itemsCount )
{
	int itemSize = sizeof( U16 );
	size_t bytesCount = itemsCount * itemSize;
	ssize_t retWrite = write( fd, pCode, bytesCount );
	U32 retItemsCount;
	if( retWrite < 0 )  //failed
		return retWrite;
	retItemsCount = retWrite / itemSize;
	return retItemsCount;
}

I32 EM9118_ADReadOnceCode( int fd, I32 delayUS, U16 adCode[AD_CH_COUNT] )
{

	struct timeval clkStart;
	struct timeval clkNow;

	gettimeofday( &clkStart, NULL );
	EM9118_Outw( fd, ADDR_ADSOFTSTART, 1 );
	while( (EM9118_Inw( fd, ADDR_ADSOFTSTART) & 2) == 0 )
	{
		gettimeofday( &clkNow, NULL );
		U32 cpuTime = (clkNow.tv_sec - clkStart.tv_sec) * 1000000 +  clkNow.tv_usec - clkStart.tv_usec;
		//log_write( "EM9118_ADReadOnceCode cpuTime:%d", cpuTime );
		if( cpuTime > delayUS )
		{
			printf( "EM9118_ADReadOnceCode Failed, %d\n", cpuTime );
			return -1;
		}
	}

	int i;

	for( i = 0; i < AD_CH_COUNT; ++i )
	{
		if (g_adEnCh & (1<<i))
			adCode[i] = EM9118_Inw( fd, ADDR_FIFODATA );
		else
			adCode[i] = 0;
	}

	return 0;
}

U16 EM9118_ADReadSingle( int fd, int ch )
{
	return EM9118_Inw( fd, ADDR_SINGLE_AD_DATA_BASE + ch );
}

U32 EM9118_CTRead( int fd, int chInx )
{
	U32 l = EM9118_Inw( fd, ADDR_CT1L + chInx * 2 );
	U32 h = EM9118_Inw( fd, ADDR_CT1H + chInx * 2 );
	return h * 65536 + l;
}

int EM9118_CTOver( int fd, int chInx )
{//0没有溢出，1溢出
	U32 o = EM9118_Inw( fd, ADDR_CTOVER );
	EM9118_Outw( fd, ADDR_CTOVER, 1 << chInx );
	return (o >> chInx) & 1;
}

U8 EM9118_CTGetMode( int fd, int chInx )
{//0计数1测高频3测低频
	U16 ctMode = EM9118_Inw( fd, ADDR_CTCTRL );
	return ( ctMode >> chInx ) & 0x3;
}

int EM9118_CTSetModeAll( int fd, U16 ctMode )
{//0计数1测高频3测低频
	return EM9118_Outw( fd, ADDR_CTCTRL, ctMode );
}

int EM9118_CTSetIClkDiv( int fd, int chInx, U32 div )
{
	EM9118_Outw( fd, ADDR_CTG1H + chInx * 2, (div >> 16) & 0xffff );
	return EM9118_Outw( fd, ADDR_CTG1L + chInx * 2, div & 0xffff );
}

//2013-12-10 ZCD
int EM9118_CTClearAll( int fd )
{
	int i = 0;
	for( i = 0; i < 6; ++i )
		EM9118_CTSetIClkDiv( fd, i, 1 );
	EM9118_CTSetModeAll( fd, 0x5555 );
	usleep(1000);
	return EM9118_CTSetModeAll( fd, 0 );
}

int EM9118_CTInFifo(int fd, U16 isFifo[CT_CH_COUNT])
{
	int i = 0;
	U16 uEnCh = 0;
	for( i = 0; i < CT_CH_COUNT; ++i )
	{
		uEnCh |= (isFifo[i]&1) << i;
	}
	return EM9118_Outw( fd, ADDR_CTINFIFO, uEnCh );
}

U8 EM9118_IOReadGroup(int fd, int groupInx)
{
	switch( groupInx )
	{
	case 0:
		return EM9118_Inb( fd, ADDR_DI1TO4 );
	}
	return 0;
}

int EM9118_IOWriteGroup( int fd, int groupInx, U8 od )
{
	switch( groupInx )
	{
	case 0:
		return EM9118_Outb( fd, ADDR_DO1TO2, od );
	}
	return 0;
}

int EM9118_IOInFifo(int fd, int isFifo)
{
	EM9118_Outw( fd, ADDR_IOINFIFO, isFifo );
	return 0;
}


#define I2C_RETRIES 0x0701
#define I2C_TIMEOUT 0x0702
#define I2C_RDWR 0x0707 

#define I2C_M_TEN 0x0010
#define I2C_M_RD 0x0001
/*********定义struct i2c_rdwr_ioctl_data和struct i2c_msg，要和内核一致*******/

struct i2c_msg
{
	unsigned short addr;
	unsigned short flags;
	unsigned short len;
	unsigned char *buf;
};

struct i2c_rdwr_ioctl_data
{
	struct i2c_msg *msgs;
	int nmsgs; 
        /* nmsgs这个数量决定了有多少开始信号，对于“单开始时序”，取1*/
};

//int EM9118_ROMWriteByte( int fd, int addr, U8 data )
//{
//	int ret;
//	struct i2c_rdwr_ioctl_data e2prom_data;
//	fd=open("/dev/i2c-0",O_RDWR);
//	/*dev/i2c-0是在注册i2c-dev.c后产生的，代表一个可操作的适配器。如果不使用i2c-dev.c
//	*的方式，就没有，也不需要这个节点。
//	*/
//	if(fd<0)
//	{
//		perror("open error");
//	}
//	e2prom_data.nmsgs=2; 
//	/*
//	*因为操作时序中，最多是用到2个开始信号（字节读操作中），所以此将
//	*e2prom_data.nmsgs配置为2
//	*/
//	e2prom_data.msgs=(struct i2c_msg*)malloc(e2prom_data.nmsgs*sizeof(struct i2c_msg));
//	if(!e2prom_data.msgs)
//	{
//		perror("Write24LC64Byte: malloc error");
//		goto err;
////		exit(1);
//	}
//	ioctl(fd,I2C_TIMEOUT,1);/*超时时间*/
//	ioctl(fd,I2C_RETRIES,2);/*重复次数*/
//	/***write data to e2prom**/
//
//	e2prom_data.nmsgs=1; 
//	(e2prom_data.msgs[0]).addr=0x50;//e2prom 设备地址
//	(e2prom_data.msgs[0]).flags=0; //write
//	(e2prom_data.msgs[0]).len=3; //1个 e2prom 写入目标的地址和1个数据
//	(e2prom_data.msgs[0]).buf=(unsigned char*)malloc(3);
//	(e2prom_data.msgs[0]).buf[0]=(addr>>8) & 0xff;// e2prom 写入目标的地址
//	(e2prom_data.msgs[0]).buf[1]=addr & 0xff;// e2prom 写入目标的地址
//	(e2prom_data.msgs[0]).buf[2]=data;//the data to write
//
//    ret=ioctl(fd,I2C_RDWR,(unsigned long)&e2prom_data);
//	if(ret<0)
//	{
//		perror("Write24LC64Byte:ioctl error1");
//		goto err;
//	}
//	close(fd);
//	usleep( 10000 );
//	return 0;
//err:
//	log_write( "Write24LC64Byte: addr:%x, data:%x", addr, data );
//	close(fd);
//	return -1;
//}

//使用9G45的i2c接口
//int EM9118_ROMReadByte( int fd, int addr, U8* data )
//{
//	int ret;
//	struct i2c_rdwr_ioctl_data e2prom_data;
//	fd=open("/dev/i2c-0",O_RDWR);
//	/*dev/i2c-0是在注册i2c-dev.c后产生的，代表一个可操作的适配器。如果不使用i2c-dev.c
//	*的方式，就没有，也不需要这个节点。
//	*/
//	if(fd<0)
//	{
//		perror("open error");
//	}
//	e2prom_data.nmsgs=2; 
//	/*
//	*因为操作时序中，最多是用到2个开始信号（字节读操作中），所以此将
//	*e2prom_data.nmsgs配置为2
//	*/
//	e2prom_data.msgs=(struct i2c_msg*)malloc(e2prom_data.nmsgs*sizeof(struct i2c_msg));
//	if(!e2prom_data.msgs)
//	{
//		perror("Read24LC64Byte: malloc error");
//		goto err;
////		exit(1);
//	}
//	ioctl(fd,I2C_TIMEOUT,1);/*超时时间*/
//	ioctl(fd,I2C_RETRIES,2);/*重复次数*/
//	/***write data to e2prom**/
//
//	e2prom_data.nmsgs=2; 
//	(e2prom_data.msgs[0]).addr=0x50;//e2prom 设备地址
//	(e2prom_data.msgs[0]).flags=0; //write
//	(e2prom_data.msgs[0]).len=2; //1个 e2prom 写入目标的地址和1个数据
//	(e2prom_data.msgs[0]).buf=(unsigned char*)malloc(2);
//	(e2prom_data.msgs[0]).buf[0]=(addr>>8) & 0xff;// e2prom 写入目标的地址
//	(e2prom_data.msgs[0]).buf[1]=addr & 0xff;// e2prom 写入目标的地址
//	(e2prom_data.msgs[1]).addr=0x50;// e2prom 设备地址 
//	(e2prom_data.msgs[1]).flags=I2C_M_RD;//read
//	(e2prom_data.msgs[1]).len=1;//读出的数据
//	(e2prom_data.msgs[1]).buf=(unsigned char*)malloc(1);//存放返回值的地址。
//	(e2prom_data.msgs[1]).buf[0]=0;//初始化读缓冲
//
//	ret=ioctl(fd,I2C_RDWR,(unsigned long)&e2prom_data);
//	if(ret<0)
//	{
//		perror("Read24LC64Byte: ioctl error2");
//		goto err;
//	}
//	*data = (e2prom_data.msgs[1]).buf[0];
//	close(fd);
//	return 0;
//err:
//	close(fd);
//	return -1;
//}

int EM9118_ROMReadByte( int fd, int addr, U8* data )
{
	int times = 0;
	EM9118_Outb(fd, ADDR_ROM_ADDRESS, addr);
	EM9118_Outb(fd, ADDR_ROM_RW, 1);
	while( (EM9118_Inb(fd, ADDR_ROM_STA)&1) == 0 && ++times < 1000 );

	if( times >= 1000 )
	{
		printf( "EM9118_ROMReadByte Error!\n");
		return -1;
	}

	*data = EM9118_Inb(fd, ADDR_ROM_DATA);
	
/*	if( times >= 100000 )
	{
		log_write( "EM9118_ROMReadByte Error!");
		return -1;
	}*/
	//log_write( "EM9118_ROMReadByte:%d,%x", addr, *data );
	return 0;
}

int EM9118_ROMWriteByte( int fd, int addr, U8 data )
{
	int times = 0;
	EM9118_Outb(fd, ADDR_ROM_ADDRESS, addr );
	EM9118_Outb(fd, ADDR_ROM_DATA, data);
	EM9118_Outb(fd, ADDR_ROM_RW, 0);
//	log_write( "EM9118_ROMWriteByte:%d, %x", addr, data );

	while( (EM9118_Inb(fd, ADDR_ROM_STA) & 2) == 2 && ++times < 100000 );

	if( times >= 100000 )
	{
		printf( "EM9118_ROMWriteByte Error!\n");
		return -1;
	}
	usleep(10000);
	return 0;
}

int EM9118_RomWFWrite( int fd, int chInx, int rangeInx, I16 wf )
{
	EM9118_ROMWriteByte( fd, ROMADDR_AD1_RANGE0_WF + chInx * ROMADDR_AD_RANGE_SIZE + rangeInx * ROMADDR_AD_RANGE0_SIZE, wf & 0xff );
	EM9118_ROMWriteByte( fd, ROMADDR_AD1_RANGE0_WF + chInx * ROMADDR_AD_RANGE_SIZE + rangeInx * ROMADDR_AD_RANGE0_SIZE + 1, (wf>>8) & 0xff );
	return ZT_SUCCESS;
}

int EM9118_RomWZWrite( int fd, int chInx, int rangeInx, I16 wz )
{
	EM9118_ROMWriteByte( fd, ROMADDR_AD1_RANGE0_WZ + chInx * ROMADDR_AD_RANGE_SIZE + rangeInx * ROMADDR_AD_RANGE0_SIZE, wz & 0xff );
	EM9118_ROMWriteByte( fd, ROMADDR_AD1_RANGE0_WZ + chInx * ROMADDR_AD_RANGE_SIZE + rangeInx * ROMADDR_AD_RANGE0_SIZE + 1, (wz>>8) & 0xff );
	return ZT_SUCCESS;
}

int EM9118_RomWFWZWrite( int fd, int chInx, int rangeInx, I16 wz, I16 wf )
{
	EM9118_ROMWriteByte( fd, ROMADDR_AD1_RANGE0_WZ + chInx * ROMADDR_AD_RANGE_SIZE + rangeInx * ROMADDR_AD_RANGE0_SIZE, wz & 0xff );
	EM9118_ROMWriteByte( fd, ROMADDR_AD1_RANGE0_WZ + chInx * ROMADDR_AD_RANGE_SIZE + rangeInx * ROMADDR_AD_RANGE0_SIZE + 1, (wz>>8) & 0xff );
	EM9118_ROMWriteByte( fd, ROMADDR_AD1_RANGE0_WF + chInx * ROMADDR_AD_RANGE_SIZE + rangeInx * ROMADDR_AD_RANGE0_SIZE, wf & 0xff );
	EM9118_ROMWriteByte( fd, ROMADDR_AD1_RANGE0_WF + chInx * ROMADDR_AD_RANGE_SIZE + rangeInx * ROMADDR_AD_RANGE0_SIZE + 1, (wf>>8) & 0xff );
	return ZT_SUCCESS;
}

int EM9118_RomWFWZRead( int fd, int chInx, int rangeInx, I16* wz, I16* wf )
{
	U8 l = 0, h = 0;
	I16 vz,vf;
	EM9118_ROMReadByte( fd, ROMADDR_AD1_RANGE0_WZ + chInx * ROMADDR_AD_RANGE_SIZE + rangeInx * ROMADDR_AD_RANGE0_SIZE, &l );
	EM9118_ROMReadByte( fd, ROMADDR_AD1_RANGE0_WZ + chInx * ROMADDR_AD_RANGE_SIZE + rangeInx * ROMADDR_AD_RANGE0_SIZE + 1, &h );
	vz = (h << 8) | l;


	EM9118_ROMReadByte( fd, ROMADDR_AD1_RANGE0_WF + chInx * ROMADDR_AD_RANGE_SIZE + rangeInx * ROMADDR_AD_RANGE0_SIZE, &l );
	EM9118_ROMReadByte( fd, ROMADDR_AD1_RANGE0_WF + chInx * ROMADDR_AD_RANGE_SIZE + rangeInx * ROMADDR_AD_RANGE0_SIZE + 1, &h );
	vf = (h << 8) | l;

	if (abs(vz) > 1000)  // 判断ROM中的数是否有效
		*wz = 0;
	else
		*wz = vz;

	if (abs(vf-AD_WF_MAX) > 1000) // 判断ROM中的数是否有效
		*wf = AD_WF_MAX;
	else
		*wf = vf;

//	log_write( "EM9118_RomWFWZRead:addr: %d, %d,%d", ROMADDR_AD1_RANGE0_WZ + chInx * ROMADDR_AD_RANGE_SIZE + rangeInx * ROMADDR_AD_RANGE0_SIZE, *wz, *wf );
	return ZT_SUCCESS;
}

U32 EM9118_ECRead( int fd, int chInx )
{
	U32 h,l;
	if( chInx == 0 )
	{
		l = EM9118_Inw( fd, ADDR_EC1L ) & 0xffff;//必须先读低16位锁存
		h = EM9118_Inw( fd, ADDR_EC1H ) & 0xffff;
	}else if( chInx == 1 )
	{
		l = EM9118_Inw( fd, ADDR_EC2L ) & 0xffff;//必须先读低16位锁存
		h = EM9118_Inw( fd, ADDR_EC2H ) & 0xffff;
	}
//	log_write( "MDECBuffer:%x, %x", h,l );
	return h * 65536 + l;
}

int EM9118_ECClear( int fd, int clrCode )
{
	EM9118_Outw( fd, ADDR_ECCLEAR, clrCode );
	return 0;
}

int EM9118_GetSysErrorCode( int fd )
{//ZCD 13-10-15
	int errCode;
	int ret = ioctl( fd, PM518_IOC_GETERRORCODE, &errCode );
	if( ret < 0 )
		return ret;
	else
		return errCode;
}

void EM9118_FeedDog( int fd )
{
	EM9118_WriteM( fd, 0xFFFFFE40, 0xA5000001 );

//	log_write( "EM9118_FeedDog" );
}

int EM9118_PWMSetFreq( int fd, int chInx, U16 t )
{
	return EM9118_Outw( fd, ADDR_PWMT0 + chInx * 3, t );
}

int EM9118_PWMSetWide( int fd, int chInx, U16 w )
{
//	log_write( "EM9118_PWMSetWide:%d, %d", ADDR_PWMW0 + chInx * 3, w );
	return EM9118_Outw( fd, ADDR_PWMW0 + chInx * 3, w );
}

int EM9118_PWMSetStepCnt( int fd, int chInx, U16 stepCnt )
{
	return EM9118_Outw( fd, ADDR_PWMS0 + chInx * 3, stepCnt );
}

int EM9118_PWMSetPhaseAll( int fd, U8 phase )
{
	return EM9118_Outw( fd, ADDR_PWMPHASE, phase );
}

int EM9118_PWMEnableAll( int fd, U8 e )
{
	return EM9118_Outw( fd, ADDR_PWMEN, e );
}

U8 EM9118_PWMIsOver( int fd )
{
	return EM9118_Inw( fd, ADDR_PWMEN ) & 0xff;
}

void EM9118_IOSetMode( int fd, U16 doMode[DO_CH_COUNT] )
{
	U16 uDoMode = ((doMode[1]&3) << 2) | (doMode[0]&3);
	EM9118_Outw( fd, ADDR_IOCTRL, uDoMode );
//	log_write( "EM9118_IOSetMode:%x", uDoMode );
}

I32 EM9118_ADSetRangeAll( int fd, U16 rangeInx )
{
	if( rangeInx > 1 )
		return ZT_FALSE;
	U16 reg = (rangeInx<<2) + (rangeInx<<1) + rangeInx;
	EM9118_Outw( fd, ADDR_ADRANGE, reg );
	return ZT_SUCCESS;
}

I32 EM9118_ADSetGainAll( int fd, U16 gainInx )
{
	EM9118_Outw( fd, ADDR_ADGAIN, gainInx );
	return ZT_SUCCESS;
}

I32 EM9118_ADGetGainAll( int fd, U16* gainInx )
{
	*gainInx = EM9118_Inw( fd, ADDR_ADGAIN );
	return ZT_SUCCESS;
}

I32 EM9118_HCSetETRGroupCount( int fd, U32 groupCount )
{
	EM9118_Outw( fd, ADDR_ETRGROUPCNT_L, groupCount & 0xffff );
	return EM9118_Outw( fd, ADDR_ETRGROUPCNT_H, (groupCount>>16) & 0xffff );
}

I32 EM9118_ReadHFifo( int fd, U32 overTimeUS, U16 codeCount, U16* adCode )
{
	struct timeval clkStart;
	struct timeval clkNow;
	gettimeofday( &clkStart, NULL );
	U32 i;
	for( i = 0; i < codeCount; ++i )
	{
		while( !(EM9118_Inw( fd, ADDR_CTRLCODE ) & AD_HFIFO_EMPTY) )
		{
			gettimeofday( &clkNow, NULL );
			I32 cpuTime = (clkNow.tv_sec - clkStart.tv_sec) * 1000000 + clkNow.tv_usec - clkStart.tv_usec;
			//		log_write( "EM9118_ADReadOnceCode cpuTime:%d", cpuTime );
			if( cpuTime > overTimeUS )
			{
//				log_write( "EM9118_ReadHFifo Failed, time: %d, count:%d", cpuTime, i );
				return i;
			}
		}
		adCode[i] = EM9118_Inw( fd, ADDR_FIFODATA );//为了以后做平均时用
	}
	return i;
}

I32 EM9118_GetDeviceType( int fd )
{
	return EM9118_Inw( fd, ADDR_ID );
}

I32 EM9106_DaSetCtrl( int fd, int ctrlCode )
{
	EM9118_Outw( fd, ADDR_DACTRL, ctrlCode );
	return 0;
}

I32 EM9106_DaSetCodeOnce( int fd, int chInx, int daCode )
{
	EM9118_Outw( fd, ADDR_DACH, chInx );
	EM9118_Outw( fd, ADDR_DACODE, daCode );
	ZcdTimer_Init(&tv);
	int ext = 0;
	while( EM9118_Inw( fd, ADDR_DACTRL ) & 0x8000 )
	{
		I64 tt = ZcdTimer_GetTimeInterval( &tv );
		if( tt > 10000 )//10ms
		{
			printf( "DA Set time out!\n" );
			return -1;
		}
	}
	return 0;
}

I32 EM9106_DaSetRange( int fd, U16 rangeCode )
{
	EM9118_Outw( fd, ADDR_DARANGE, rangeCode );
	return 0;
}

I32 EM9106_DaSetEnCh( int fd, U16 enCh )
{
	EM9118_Outw( fd, ADDR_DAEN, enCh );
	return 0;
}

I32 EM9106_DaSetFreqDiv( int fd, U32 freqDiv )
{
	EM9118_Outw( fd, ADDR_DAFREQDIV, freqDiv & 0xffff );
	EM9118_Outw( fd, ADDR_DAFREQDIV+1, (freqDiv >> 16) & 0xffff );
	return 0;
}

I32 EM9106_DaHFifoCanWriteCnt( int fd, U16* canWriteCnt )
{
	U16 canReadCnt = EM9118_Inw( fd, ADDR_DAFIFOCNT );
	if( canWriteCnt )
		*canWriteCnt = 2048 - canReadCnt;
	return 0;
}

I32 EM9106_DaWriteHFifo( int fd, U16* daCode, U16 codeCount )
{
	int i = 0;
	for( i = 0; i < codeCount; ++i )
		EM9118_Outw( fd, ADDR_DAFIFO, daCode[i] );
	return 0;
}

I32 EM9106_DaHFifoClear( int fd )
{
	U16 ctrl = EM9118_Inw( fd, ADDR_DACTRL );
	ctrl |= 8;
	EM9118_Outw( fd, ADDR_DACTRL, ctrl );
	ctrl &= ~8;
	EM9118_Outw( fd, ADDR_DACTRL, ctrl );
	ctrl = EM9118_Inw( fd, ADDR_DACTRL );
//	log_write( "%s,ctrl:%x", __FUNCTION__, ctrl );
	return 0;
}

I32 EM9106_DaStart( int fd )
{
	U16 ctrl = EM9118_Inw( fd, ADDR_DACTRL );
	ctrl |= 4;//使能DA输出
	ctrl &= ~8;//不清空FIFO
	EM9118_Outw( fd, ADDR_DACTRL, ctrl );
//	printf( "%s:ctrl:%x\n", __FUNCTION__, ctrl );
	return 0;
}

I32 EM9106_DaStop( int fd )
{
	U16 ctrl = EM9118_Inw( fd, ADDR_DACTRL );
	ctrl &= ~4;
	EM9118_Outw( fd, ADDR_DACTRL, ctrl );
	printf( "%s:ctrl:%x\n", __FUNCTION__, ctrl );
	return 0;
}

I32 EM9106BD_IOSetDir( int fd, int dirReg )
{
	U16 ctrl = EM9118_Inw( fd, ADDR_IOCTRL );
	ctrl &= ~0xf0;
	ctrl |= (dirReg & 0xf) << 4;
	EM9118_Outw( fd, ADDR_IOCTRL, ctrl );
	printf( "%s:ctrl:%x\n", __FUNCTION__, ctrl );
	return 0;
}

I32 EM9118BD_DaIrqEnable( int fd, int irqEnable )
{
	U16 ctrl = EM9118_Inw( fd, ADDR_CTRLCODE );
	if( irqEnable )
		ctrl |= IRQ_DAFIFO;
	else
		ctrl &= ~IRQ_DAFIFO;
	EM9118_Outw( fd, ADDR_CTRLCODE, ctrl );
//	printf( "%s:ctrl:%x\n", __FUNCTION__, ctrl );
	return 0;
}

I32 EM9118BD_AdIrqEnable( int fd, int irqEnable )
{
	U16 ctrl = EM9118_Inw( fd, ADDR_CTRLCODE );
	if( irqEnable )
		ctrl |= IRQ_ADFIFO;
	else
		ctrl &= ~IRQ_ADFIFO;
	EM9118_Outw( fd, ADDR_CTRLCODE, ctrl );
//	printf( "%s:ctrl:%x\n", __FUNCTION__, ctrl );
	return 0;
}
